<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <title>data-table</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>

  <script type="module">
window.emojiByType = {
  a: '😎',
  b: '💰',
  c: '🚔',
  d: '💕',
  e: '👍',
  f: '🍌'
};
</script>

  <dom-module id="data-popup">
    <template strip-whitespace>
      <style>
        :host {
          display: inline-block;
          background: lightblue;
          border-radius: 10px;
          border-bottom-left-radius: 0;
          border: 1px solid #aaa;
          box-shadow: 3px 3px 5px #535353;
          padding: 5px;
          z-index: 1;
        }
      </style>
      <slot></slot>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'data-popup'
});
</script>
  </dom-module>

  <dom-module id="data-cell">
    <template strip-whitespace>
      <style>
        :host {
          flex: 1;
          border: 2px solid #aaa;
          padding: 5px;
          position: relative;
          background: #eee;
        }
        data-popup {
          display: none;
          position: absolute;
          bottom: calc(100% - 15px);
          left: calc(100% - 15px);
        }
        :host(:hover) data-popup {
          display: inline-block;
        }
        :host([change=up]) {
          background: #afa;
        }
        :host([change=down]) {
          background: #faa;
        }
        .type {
          display: inline-block;
          border-radius: 100%;
          box-sizing: border-box;
          padding: 3px 0;
          background: #aaa;
          margin-right: 5px;
          height: 30px;
          width: 30px;
          text-align: center;
        }
      </style>
      <div class="type">{{computeTypeIcon(type)}}</div>
      {{toFixed(value)}}
      <data-popup>{{value}}</data-popup>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'data-cell',
  properties: {
    type: {
      type: String,
      notify: true
    },
    value: {
      type: Number,
      notify: true
    },
    change: {
      reflectToAttribute: true,
      computed: 'computeChange(value)'
    }
  },
  attached: function() {
    this.fire('register-cell');
  },
  computeChange: function(value) {
    var prev = this._prev;
    this._prev = value;
    return value > prev ? 'up' : (value < prev ? 'down' : 'none');
  },
  computeTypeIcon: function(type) {
    return emojiByType[type];
  },
  toFixed: function(value) {
    return Number(value).toFixed(2);
  }
});
</script>
  </dom-module>

  <dom-module id="data-row">
    <template strip-whitespace>
      <style>
        :host {
          display: flex;
          flex-direction: row;
        }
        .title-cell {
          flex: 1;
        }
        .title {
          font-weight: bold;
        }
        .dominant {
          font-size: 0.7em;
        }
      </style>
      <div class="title-cell">
        <div class="title">{{title}}</div>
        <div class="dominant">Dominant: {{computeDominant(cells.*)}}</div>
      </div>
      <template is="dom-repeat" items="{{cells}}" as="cell">
        <data-cell type="{{cell.type}}" value="{{cell.value}}"></data-cell>
      </template>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'data-row',
  properties: {
    title: {
      type: String,
      notify: true
    },
    cells: {
      type: Array,
      notify: true
    }
  },
  computeDominant: function(info) {
    var types = this.types = info.base.reduce(function(map, i) {
      return map[i.type] = (map[i.type] || 0) + 1, map;
    }, {})
    return emojiByType[Object.keys(types).sort(function(a, b) {
      return types[b] - types[a];
    })[0]];
  }
});
</script>
  </dom-module>

  <dom-module id="data-table">
    <template strip-whitespace>
      <style>
        :host {
          display: block;
        }
      </style>
      Polymer: {{version}}<br>
      <button on-tap="toggleRunning">{{computeRunning(running)}}</button>
      <input value-as-number="{{tables::input}}" type="number" style="width:35px;" placeholder="tables">
      <input value-as-number="{{rows::input}}" type="number" style="width:35px;" placeholder="rows">
      <input value-as-number="{{columns::input}}" type="number" style="width:35px;" placeholder="columns">
      <br><br>
      <select value="{{strategy::change}}">
        <option value="reset">(Mutate in place x n), reset</option>
        <option value="reset-each">(Mutate in place, reset) x n</option>
        <option value="path">(Set path from top) x n</option>
        <option value="path-leaf">(Set path from leaf) x n</option>
      </select>
      n = <input value-as-number="{{mutations::input}}" type="number" style="width:35px;">
      <br><br>
      <h3>FPS: {{fps}}</h3>
      <h3>Op time: {{toFixed(optime, 2)}}</h3>
      <div xhidden>
        <template is="dom-repeat" items="{{tableData}}">
          <h3>Table {{index}}:</h3>
          <template is="dom-repeat" items="{{data}}" as="row">
            <data-row title="{{row.title}}" cells="{{row.cells}}"></data-row>
          </template>
        </template>
      </div>
    </template>
    <script type="module">
import { Polymer, version } from '../../lib/utils/boot.js';
var params = document.location.search.substring(1).split('&').map(p=>p.split('='))
  .reduce((m, p)=>{return m[p[0]] = p[1], m;}, {});
Polymer({
  is: 'data-table',
  properties: {
    rows: {
      type: Number,
      value: Number(params.rows) || 6
    },
    columns: {
      type: Number,
      value: Number(params.columns) || 10
    },
    tables: {
      type: Number,
      value: Number(params.tables) || 2
    },
    mutations: {
      type: Number,
      value: Number(params.mutations) || 30
    },
    strategy: {
      type: String,
      value: params.strategy || 'reset'
    },
    running: {
      type: Number,
      value: params.running === 'false' ? false : true
    },
    tableData: {
      computed: 'computeTableData(tables)'
    },
    optime: {
      value: 0
    }
  },
  observers: ['computeData(rows, columns)'],
  created: function() {
    this._fps = 0;
    this.end = performance.now() + 1000;
    var cells = this.cells = [];
    this.addEventListener('register-cell', function(e) {
      var cell = e.composedPath()[0];
      cell.id = 'cell-' + cells.length;
      cells.push(cell);
    });
  },
  toggleRunning: function() {
    this.running = !this.running;
    if (this.running) {
      this.go();
    }
  },
  computeRunning: function(running) {
    return running ? 'Pause' : 'Run';
  },
  computeData: function(rows, columns) {
    var r = [];
    for (var i=0; i<rows; i++) {
      var c = [];
      for (var j=0; j<columns; j++) {
        c.push({
          value: Math.random() * 10,
          type: ['a','b','c','d','e','f'][Math.floor(Math.random()*6)]
        });
      }
      r.push({
        cells: c,
        title: 'Row ' + i
      })
    }
    this.data = r;
  },
  computeTableData: function(tables) {
    return new Array(Number(tables));
  },
  toFixed: function(value, decimals) {
    return value.toFixed(decimals);
  },
  ready: function() {
    this.version = version || 'alacarte';
    if (!this.setProperties) {
      this.setProperties = function(props) {
        for (var p in props) {
          this.set(p, props[p]);
        }
      }
    }
    this.go();
  },
  go: function() {
    var optime = 0;
    for (var i=0; i<this.mutations; i++) {
      var type = ['a','b','c','d','e','f'][Math.floor(Math.random()*6)];
      var delta = (Math.random() > 0.5 ? -1 : 1) * (Math.random() * 5);
      var row = Math.floor(Math.random() * this.rows);
      var column = Math.floor(Math.random() * this.columns);
      var d = this.data[row].cells[column];
      if (this.strategy == 'reset' || this.strategy == 'reset-each') {
        d.type = type;
        d.value += delta;
        if (this.strategy == 'reset-each') {
          var start = performance.now();
          this.set('data', this.data);
          optime += (performance.now() - start);
        }
      } else if (this.strategy == 'path') {
        var path = ['data', row, 'cells', column].join('.');
        var props = {};
        props[path + '.type'] = type;
        props[path + '.value'] = d.value + delta;
        var start = performance.now();
        this.setProperties(props);
        optime += (performance.now() - start);
      } else if (this.strategy == 'path-leaf') {
        var c = this.cells[Math.floor(this.cells.length * Math.random())];
        var props = {
          type: type,
          value: c.value + delta
        };
        var start = performance.now();
        c.setProperties(props);
        optime += (performance.now() - start);
      }
    }
    if (optime) {
      this.optime = (this.optime * 9 + (optime / this.mutations)) / 10;
      // this.optime = optime / this.mutations;
    }
    if (this.strategy == 'reset') {
      var start = performance.now();
      this.set('data', this.data);
      this.optime = (this.optime * 9 + (performance.now() - start)) / 10;
      // this.optime = performance.now() - start;
    }
    this._fps++;
    if (performance.now() > this.end) {
      this.fps = this._fps;
      this._fps = 0;
      this.end = performance.now() + 1000;
    }
    var self = this;
    if (this.running) {
      requestAnimationFrame(function() {
        self.go();
      });
    }
  }
});
</script>
  </dom-module>

  <data-table id="table"></data-table>


</body>
</html>
